<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\UX\LazyImage\Tests\BlurHash;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\UX\LazyImage\BlurHash\BlurHash;
use Symfony\UX\LazyImage\BlurHash\BlurHashInterface;
use Symfony\UX\LazyImage\Tests\Fixtures\BlurHash\LoggedFetchImageContent;
use Symfony\UX\LazyImage\Tests\Kernel\TwigAppKernel;

/**
 * @author Titouan Galopin <galopintitouan@gmail.com>
 *
 * @internal
 */
class BlurHashTest extends TestCase
{
    public function testEncode()
    {
        $kernel = new TwigAppKernel('test', true);
        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $this->assertSame(
            BlurHash::intervention3() ? 'LnMtaO9FD%IU%MRjayRj~qIUM{of' : 'L54ec*~q_3?bofoffQWB9F9FD%IU',
            $blurHash->encode(__DIR__.'/../Fixtures/logo.png')
        );
    }

    public function testWithCustomGetImageContent()
    {
        $kernel = new class('test', true) extends TwigAppKernel {
            public function registerContainerConfiguration(LoaderInterface $loader): void
            {
                parent::registerContainerConfiguration($loader);

                $loader->load(static function (ContainerBuilder $container) {
                    $container->loadFromExtension('lazy_image', [
                        'fetch_image_content' => 'logged_get_image_content',
                    ]);

                    $container
                        ->setDefinition('logged_get_image_content', new Definition(LoggedFetchImageContent::class))
                        ->setPublic('true')
                    ;
                });
            }
        };

        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $loggedGetImageContent = $container->get('logged_get_image_content');
        $this->assertInstanceOf(LoggedFetchImageContent::class, $loggedGetImageContent);
        $this->assertEmpty($loggedGetImageContent->logs);

        $this->assertSame(
            BlurHash::intervention3() ? 'LnMtaO9FD%IU%MRjayRj~qIUM{of' : 'L54ec*~q_3?bofoffQWB9F9FD%IU',
            $blurHash->encode(__DIR__.'/../Fixtures/logo.png')
        );

        $this->assertCount(1, $loggedGetImageContent->logs);
        $this->assertSame(__DIR__.'/../Fixtures/logo.png', $loggedGetImageContent->logs[0]);
    }

    public function testEnsureCacheIsNotUsedWhenNotConfigured()
    {
        $kernel = new TwigAppKernel('test', true);
        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $this->assertInstanceOf(BlurHash::class, $blurHash);
        $this->assertNull($this->extractCache($blurHash));
    }

    public function testEnsureCacheIsUsedWhenConfigured()
    {
        $kernel = new class('test', true) extends TwigAppKernel {
            public function registerContainerConfiguration(LoaderInterface $loader): void
            {
                parent::registerContainerConfiguration($loader);

                $loader->load(static function (ContainerBuilder $container) {
                    $container->loadFromExtension('framework', [
                        'cache' => [
                            'pools' => [
                                'cache.lazy_image' => [
                                    'adapter' => 'cache.adapter.array',
                                ],
                            ],
                        ],
                    ]);

                    $container->loadFromExtension('lazy_image', [
                        'cache' => 'cache.lazy_image',
                    ]);

                    $container->setAlias('test.cache.lazy_image', 'cache.lazy_image')->setPublic(true);
                });
            }
        };

        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $this->assertInstanceOf(BlurHash::class, $blurHash);
        $this->assertInstanceOf(CacheInterface::class, $this->extractCache($blurHash));
    }

    public function testCreateDataUriThumbnail()
    {
        $kernel = new TwigAppKernel('test', true);
        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $this->assertInstanceOf(BlurHash::class, $blurHash);
        $this->assertNull($this->extractCache($blurHash));

        $this->assertSame(
            BlurHash::intervention3() ? '' : '',
            $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58)
        );
    }

    public function testCreateDataUriThumbnailWithCache()
    {
        $kernel = new class('test', true) extends TwigAppKernel {
            public function registerContainerConfiguration(LoaderInterface $loader): void
            {
                parent::registerContainerConfiguration($loader);

                $loader->load(static function (ContainerBuilder $container) {
                    $container->loadFromExtension('framework', [
                        'cache' => [
                            'pools' => [
                                'cache.lazy_image' => [
                                    'adapter' => 'cache.adapter.array',
                                ],
                            ],
                        ],
                    ]);

                    $container->loadFromExtension('lazy_image', [
                        'cache' => 'cache.lazy_image',
                    ]);

                    $container->setAlias('test.cache.lazy_image', 'cache.lazy_image')->setPublic(true);
                });
            }
        };

        $kernel->boot();
        $container = $kernel->getContainer()->get('test.service_container');

        /** @var BlurHashInterface $blurHash */
        $blurHash = $container->get('test.lazy_image.blur_hash');

        $this->assertInstanceOf(BlurHash::class, $blurHash);
        $this->assertInstanceOf(ArrayAdapter::class, $cache = $this->extractCache($blurHash));

        $this->assertEmpty($cache->getValues());

        $this->assertSame(
            BlurHash::intervention3() ? '' : '',
            $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58)
        );

        $this->assertNotEmpty($cache->getValues());

        $this->assertSame(
            BlurHash::intervention3() ? '' : '',
            $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58)
        );

        $this->assertNotEmpty($cache->getValues());
    }

    public function testTwigExtension()
    {
        $kernel = new TwigAppKernel('test', true);
        $kernel->boot();
        $twig = $kernel->getContainer()->get('test.service_container')->get('twig');
        $output = $twig->createTemplate(<<<TWIG
            {{ blur_hash(file) }}
            {{ data_uri_thumbnail(file, 234, 58) }}
            TWIG)->render(['file' => __DIR__.'/../Fixtures/logo.png']);

        if (BlurHash::intervention3()) {
            $expected = <<<OUTPUT
                LnMtaO9FD%IU%MRjayRj~qIUM{of
                
                OUTPUT;
        } else {
            $expected = <<<OUTPUT
                L54ec*~q_3?bofoffQWB9F9FD%IU
                
                OUTPUT;
        }

        $this->assertSame($expected, $output);

        $kernel->shutdown();
    }

    private function extractCache(BlurHash $blurHash): ?CacheInterface
    {
        return \Closure::bind(fn () => $this->cache, $blurHash, BlurHash::class)();
    }
}
